import { isInterval } from '@/ayaka'
import { DpHarvestTask } from './types'
import { CreepRoles } from '@/modules/structures/spawn/types'
import SpawnController from '@/modules/structures/spawn'
import { BodyPartArrayType } from '@/utils/common'
import { getFreeSpace, unserializePos } from '@/utils/position'
import { goTo } from '@/modules/move'

/**
 * 孵化 deposit 采集者
 */
export const spawnDpHarvester = function (room: MyRoom, task: DpHarvestTask, dpHarvesters: Creep[]) {
    if (!isInterval(31)) return

    if (SpawnController.searchSpawnTaskByRole(room, CreepRoles.dpHarvester).length) return

    const { freePos, distance } = task
    // 存活时间较长的爬
    const longTimeCreeps = dpHarvesters.filter((creep) => {
        return creep.spawning || (creep.ticksToLive && creep.ticksToLive > (distance || 150) + creep.body.length * 3)
    })
    // 最多一次性出 3 个
    if (longTimeCreeps.length >= Math.min(freePos, 3)) return

    const creepName = SpawnController.addSpawnTask(room, {
        role: CreepRoles.dpHarvester,
        body: getDpHarvesterBody(room, task),
        defaultAdaption: true,
    })
    if (creepName) {
        task.harvesters.push(creepName)
    }
}

/**
 * 生成 deposit 采集者身体部件
 */
const getDpHarvesterBody = function (room: Room, task: DpHarvestTask): BodyPartArrayType {
    const { lastCooldown } = task
    if (lastCooldown < 40) {
        return [
            [WORK, 20],
            [CARRY, 10],
            [MOVE, 20],
        ]
    } else {
        return [
            [WORK, 23],
            [CARRY, 4],
            [MOVE, 23],
        ]
    }
}

/**
 * deposit 采集者工作
 */
export const dpHarvesterWork = function (room: MyRoom, task: DpHarvestTask, creeps: Creep[]) {
    const { depositId, posStr, depositType } = task

    const depositPos = unserializePos(posStr)
    if (!depositPos) {
        console.log(`[dpHarvesterWork] invalid posStr: ${posStr}`)
        task.done = true
        return
    }

    const targetRoom = Game.rooms[depositPos.roomName]
    let deposit: Deposit | null = null
    if (targetRoom && !(deposit = Game.getObjectById(depositId) as Deposit)) {
        console.log(`[dpHarvesterWork] invalid depositId: ${depositId}`)
        task.done = true
        return
    }

    // 更新数据
    if (deposit) {
        task.lastCooldown = deposit.lastCooldown
        task.ticksToDecay = deposit.ticksToDecay
        // 冷却时间过长或者即将消失就不再采集
        if (task.lastCooldown > 100 || task.ticksToDecay < 2000) {
            task.done = true
        }
    }

    creeps.forEach((creep) => {
        if (creep.memory.boost && !creep.memory.boost.done) {
            return
        }

        if (creep.hits < creep.hitsMax) {
            if (!task.restartTime || task.restartTime < Game.time) {
                task.restartTime = Game.time + 1500
            }
        }

        // 出发
        if (creep.room.name !== depositPos.roomName) {
            goTo(creep, depositPos, { preferHighway: true })
            return
        }

        if (!deposit && !(deposit = Game.getObjectById(depositId) as Deposit)) {
            task.done = true
            return
        }

        if (!creep.memory._reached) {
            task.distance = Math.min(task.distance || 500, 1500 - creep.ticksToLive!)
            creep.memory._reached = true
        }

        if (creep.pos.isNearTo(deposit)) {
            creep.memory.stand = true

            if (!deposit.cooldown && creep.store.getFreeCapacity() > 0) {
                creep.harvest(deposit)
            }

            // 如果快死了就把资源转移给邻近的寿命最大的爬
            if (creep.ticksToLive! < 10 && creeps.length >= 2 && creep.store[depositType] > 0) {
                const nearCreeps = creeps.filter((c) => {
                    return (
                        c.my &&
                        c.ticksToLive! > creep.ticksToLive! &&
                        c.store.getFreeCapacity() > 0 &&
                        creep.pos.isNearTo(c)
                    )
                })
                if (nearCreeps.length) {
                    nearCreeps.sort((a, b) => b.ticksToLive! - a.ticksToLive!)
                    creep.transfer(nearCreeps[0], depositType)
                }
            }

            return
        }

        // 看一下 deposit 周围是否有空闲的位置
        const freePos = getFreeSpace(deposit.pos, { ignoreCreep: false })
        if (freePos.length) {
            // 移动到 deposit 附近
            creep.moveTo(freePos[0])
            return
        }

        // 移动到附近
        if (creep.pos.getRangeTo(deposit) > 5) {
            goTo(creep, deposit.pos, { range: 5 })
            return
        }
    })
}
